"""
lasted edited at 2018-6-21 by Stone

Editing Logs:
    2018-6-12 by Stone
1. The method to construct the shape of the objects is so complicated, and the data to specify the shape of objects
is rather more, so I separate them here.
2. "xx" class in main code is correspondingly named "xxShape" here.
3. All the unit of length is meter.
4. Create the function "move" and "moveTo" to make it more explicit to construct the buildings,
instead of the old way that straightly set the pos. (like the real operation in 3D modeling software)

    2018-6-21
1.Little change for compatibility to main program.

data source:
    car: https://wenku.baidu.com/view/f6a7573a67ec102de3bd890f.html
    bus: https://wenku.baidu.com/view/06e54dd6b9f3f90f76c61bec.html
"""

from visual import *
import random
pos = vector


# ===== functions =====
def move(obj, dis):  # dis = displacement
    """move the obj against the displacement"""
    obj.pos += dis


def move_to(obj, new_pos):
    """move the obj to the new_pos"""
    obj.pos = new_pos


# ===== classes =====
class VehicleShape:
    """model available is 'car' or 'bus', axis is a vector where it orients to."""
    model = {
        "car": {"length": 4.3, "width": 1.7, "height": 1.4},
        "bus": {"length": 12.0, "width":2.5, "height": 3.3}
    }

    def __init__(self, model):
        self.__color = (1, random.random(), random.random())
        self.__length = VehicleShape.model[model]['length']
        self.__width  = VehicleShape.model[model]['width']
        self.__height = VehicleShape.model[model]['height']

        self.body = self.construct_shape()

    def get_size(self):
        return {'length': self.__length, 'width':self.__width, 'height': self.__height}

    def construct_shape(self):
        up = (0, 0, 1)
        b = box(length=self.__length, width=self.__width, height=self.__height, color=self.__color,up=up)
        b.pos[1] += self.__height / 2.0

        return b


class CrossRoadShape:

    def __init__(self, frame):
        self.f = frame          # the frame is visual.frame object
        self.__body = self.f      # to provide uniform format for Shape classes

        # the bricks used to border the road, "fl" means front left, and "fm" means front middle, etc.
        self.bricks = \
            {"fl": None, "fm": None, "fr": None,
             "bl": None, "bm": None, "br": None,
             "lf": None, "lm": None, "lb": None,
             "rf": None, "rm": None, "rb": None
             }
        self.color = (0,1,0)
        self.width = 3.5  # width of the road of one lane, Chinese Standard for is 3.5m per lane
        self.length = 20
        self.brickLength    = self.length    # length of the road we show
        self.brickThickness = 0.5            # thickness of bricks
        self.brickHeight    = 1

        # self.construct_shape()

    def construct_shape(self):
        for idx in self.bricks:
            # create bricks
            self.bricks[idx] = box(color=self.color, frame=self.f,
                                    length=self.brickLength, width=self.brickThickness, height=self.brickHeight,
                                   )
            # place bricks
            if idx[0] == 'f' or idx[0] == 'b':
                self.bricks[idx].rotate(angle=pi/2, axis=self.f.up)
                if idx[1] == 'l':
                    delta = vector(-self.width - self.brickThickness, 0, 0)
                    move(self.bricks[idx], delta)
                elif idx[1] == 'r':
                    delta = vector( self.width + self.brickThickness, 0, 0)
                    move(self.bricks[idx], delta)
            else:
                if idx[1] == 'f':
                    delta = vector(0, self.width + self.brickThickness, 0)
                    move(self.bricks[idx], delta)
                elif idx[1] == 'b':
                    delta = vector(0,-self.width - self.brickThickness, 0)
                    move(self.bricks[idx], delta)


if __name__ == '__main__':
    scene.lights=[]
    scene.ambient = color.gray(0.8)
    scene.forward = (0,1,0)
    scene.up = (0,0,1)
    arrow(axis=vector(1,0,0)*10, color=(1,0,0))
    arrow(axis=vector(0,1,0)*10, color=(0,1,0))
    arrow(axis=vector(0,0,1)*10, color=(0,0,1))
    s = sphere()  # center flag
    crd = CrossRoadShape(frame())

    if crd.ifShow_LaneGuides:
        crd.visual_laneGuides()

    while True:
        rate(1)
        #print "up, forward: ",scene.up, scene.forward